package com.poetry.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.poetry.constant.FormatConstant;
import com.poetry.constant.LoginConstant;
import com.poetry.constant.RedisConstant;
import com.poetry.domain.dto.LoginDTO;
import com.poetry.domain.dto.UserDTO;
import com.poetry.domain.po.Admin;
import com.poetry.exception.R;
import com.poetry.exception.UnauthorizedException;
import com.poetry.mapper.AdminMapper;
import com.poetry.service.IAdminService;
import com.poetry.util.AliOssUtil;
import com.poetry.util.EmailUtil;
import com.poetry.util.UserContext;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin>
        implements IAdminService {
    @Resource
    private EmailUtil emailUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private AliOssUtil aliOssUtil;

    @Override
    public R<String> login(LoginDTO loginDTO) {
        if (!emailUtil.checkEmail(loginDTO.getEmail())) {
            return R.error("邮箱格式错误", 404);
        }
        Admin admin = query().eq("email", loginDTO.getEmail()).one();
        if (!emailUtil.verifyCode(loginDTO.getEmail(), loginDTO.getCode())) {
            return R.error("无效验证码", 404);
        }
        String password = loginDTO.getPassword();
        if (password.length() < 8 || password.length() > 16) {
            return R.error("密码长度8~16位", 404);
        }
        if (!Pattern.compile(FormatConstant.REGEX).matcher(password).matches()) {
            return R.error("密码需要同时包含数字、字母和特殊符号中的至少两种类型", 404);
        }
        password = DigestUtils.md5DigestAsHex((LoginConstant.SALT + loginDTO.getPassword()).getBytes());
        if (admin != null && !admin.getPassword().equals(password)) {
            return R.error("密码错误", 404);
        }
        if (admin == null) {
            return R.error("管理员账号不存在");
        }
        String token = UUID.randomUUID().toString();
        UserDTO userDTO = BeanUtil.copyProperties(admin, UserDTO.class);
        userDTO.setIcon("111");
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor(((fieldName, fieldValue) -> fieldValue.toString())));
        String tokenKey = RedisConstant.LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        stringRedisTemplate.expire(tokenKey, RedisConstant.LOGIN_USER_TTL, TimeUnit.MINUTES);
        return R.success("登录成功", token);
    }

    @Override
    public R<String> sendVerificationCode(LoginDTO loginDTO) {
        if (!emailUtil.checkEmail(loginDTO.getEmail())) {
            return R.error("邮箱格式错误");
        }
        emailUtil.saveCode(loginDTO.getEmail());
        try {
            emailUtil.sendVerificationCode(loginDTO.getEmail());
        } catch (Exception e) {
            throw new UnauthorizedException("邮箱发送失败");
        }
        return R.success(null, "验证码发送成功");
    }

    @Override
    @Transactional
    public R<String> resetPassword(LoginDTO loginDTO) {
        Admin admin = this.getById(UserContext.getUserId());
        String password = loginDTO.getPassword();
        if (!emailUtil.checkEmail(loginDTO.getEmail())) {
            return R.error("邮箱格式错误", 404);
        }
        if (password.length() < 8 || password.length() > 16) {
            return R.error("密码长度8~16位", 404);
        }
        if (!Pattern.compile(FormatConstant.REGEX).matcher(password).matches()) {
            return R.error("密码需要同时包含数字、字母和特殊符号中的至少两种类型", 404);
        }
        if (!emailUtil.verifyCode(loginDTO.getEmail(), loginDTO.getCode())) {
            return R.error("无效验证码", 404);
        }
        if (admin.getEmail().equals(loginDTO.getEmail())) {
            return R.error("邮箱验证失败");
        }
        password = DigestUtils.md5DigestAsHex((LoginConstant.SALT + loginDTO.getPassword()).getBytes());
        admin.setPassword(password);
        boolean isSuccess = this.updateById(admin);
        if (!isSuccess) {
            return R.error("重置密码失败");
        }
        return R.success(null, "密码重置成功");
    }

    @Override
    public R<Admin> updateMessage(UserDTO userDTO) {
        Admin admin = this.getById(UserContext.getUserId());
        String newName = userDTO.getUsername();
        if (newName.isEmpty() || newName.length() > 12) {
            return R.error("用户名称长度只能在1-12之间");
        }
        admin.setUsername(newName);
        boolean isSuccess = this.updateById(admin);
        if (!isSuccess) {
            return R.error("设置失败");
        }
        return R.success("用户名称设置成功", admin);
    }

    @Override
    @Transactional
    public R<String> createAdmin(LoginDTO loginDTO) {
        Admin admin = new Admin();
        if (!emailUtil.checkEmail(loginDTO.getEmail())) {
            return R.error("邮箱格式错误");
        }
        String password = loginDTO.getPassword();
        if (password.length() < 8 || password.length() > 16) {
            return R.error("密码长度8~16位", 404);
        }
        if (!Pattern.compile(FormatConstant.REGEX).matcher(password).matches()) {
            return R.error("密码需要同时包含数字、字母和特殊符号中的至少两种类型", 404);
        }
        password = DigestUtils.md5DigestAsHex((LoginConstant.SALT + loginDTO.getPassword()).getBytes());
        admin.setEmail(loginDTO.getEmail());
        admin.setPassword(password);
        boolean isSuccess = this.save(admin);
        if (!isSuccess) {
            return R.error("管理员账号创建失败");
        }
        return R.success(null, "创建管理员账号成功");
    }

    @Override
    public R<String> uploadFile(MultipartFile file) {
        try {
            return R.success("文件上传成功", aliOssUtil.uploadFile(file));
        } catch (Exception e) {
            throw new UnauthorizedException("文件上传失败");
        }
    }
}
